125 lines · 5.2 KB
1 ---
2 import Repo from '../../../layouts/Repo.astro';
3 import { apiGet } from '../../../lib/api';
4
5 const { owner, repo } = Astro.params;
6 const cookie = Astro.request.headers.get('cookie') || '';
7
8 let repoData: any = null;
9 let tree: any = null;
10 let readme: any = null;
11 let branches: any = null;
12 let activity: any[] = [];
13 let error = '';
14
15 try {
16 repoData = await apiGet(`/api/repos/${owner}/${repo}`, cookie);
17 branches = await apiGet(`/api/repos/${owner}/${repo}/branches`, cookie);
18 tree = await apiGet(`/api/repos/${owner}/${repo}/tree/${repoData.default_branch || 'main'}`, cookie);
19
20 // Try to find and load README
21 const readmeEntry = tree.entries?.find((e: any) =>
22 /^readme(\.(md|txt|rst))?$/i.test(e.name) && e.type === 'file'
23 );
24 if (readmeEntry) {
25 readme = await apiGet(
26 `/api/repos/${owner}/${repo}/blob/${repoData.default_branch || 'main'}/${readmeEntry.name}`,
27 cookie
28 );
29 }
30
31 activity = await apiGet(`/api/repos/${owner}/${repo}/activity`, cookie);
32 } catch (e: any) {
33 error = e.message;
34 }
35
36 const ref = repoData?.default_branch || 'main';
37 const cloneUrl = `${new URL(Astro.request.url).origin}/${owner}/${repo}.git`;
38 ---
39
40 <Repo owner={owner!} repo={repo!} activeTab="code" ref={ref}>
41 {error && <div class="flash-error">{error}</div>}
42
43 {repoData && (
44 <>
45 {/* Clone URL */}
46 <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px;">
47 <div style="display: flex; align-items: center; gap: 8px;">
48 <span style="font-size: 0.875rem; color: var(--text-muted);">Branch:</span>
49 <span class="btn" style="font-size: 0.8125rem;">{ref}</span>
50 </div>
51 <div style="display: flex; align-items: center; gap: 8px;">
52 <code style="background: var(--bg-tertiary); padding: 4px 12px; border-radius: var(--radius); border: 1px solid var(--border); font-size: 0.8125rem; color: var(--text-muted);">
53 git clone {cloneUrl}
54 </code>
55 </div>
56 </div>
57
58 {/* File listing */}
59 {tree && (
60 <div class="card" style="padding: 0; overflow: hidden;">
61 <table style="width: 100%; border-collapse: collapse;">
62 <tbody>
63 {tree.entries.map((entry: any) => (
64 <tr style="border-bottom: 1px solid var(--border);">
65 <td style="padding: 8px 16px; font-size: 0.875rem;">
66 <span style="color: var(--text-muted); margin-right: 8px;">
67 {entry.type === 'dir' ? '📁' : '📄'}
68 </span>
69 {entry.type === 'dir' ? (
70 <a href={`/${owner}/${repo}/tree/${ref}/${entry.name}`}>{entry.name}</a>
71 ) : (
72 <a href={`/${owner}/${repo}/blob/${ref}/${entry.name}`}>{entry.name}</a>
73 )}
74 </td>
75 </tr>
76 ))}
77 </tbody>
78 </table>
79 </div>
80 )}
81
82 {/* README */}
83 {readme && (
84 <div class="card" style="margin-top: 16px;">
85 <div style="padding: 8px 0; border-bottom: 1px solid var(--border); margin-bottom: 16px;">
86 <strong style="font-size: 0.875rem;">{readme.path}</strong>
87 </div>
88 <div style="font-size: 0.875rem; line-height: 1.6;">
89 <pre style="white-space: pre-wrap; font-family: var(--font-sans);">{readme.content}</pre>
90 </div>
91 </div>
92 )}
93
94 {/* Activity feed */}
95 {activity.length > 0 && (
96 <div style="margin-top: 20px;">
97 <h3 style="font-size: 1rem; margin-bottom: 12px; color: var(--text-muted);">Recent activity</h3>
98 <div class="card" style="padding: 0;">
99 {activity.slice(0, 10).map((event: any) => (
100 <div style="padding: 8px 16px; border-bottom: 1px solid var(--border); font-size: 0.8125rem; display: flex; justify-content: space-between; align-items: center;">
101 <div>
102 <strong style="color: var(--text);">{event.username || 'unknown'}</strong>
103 {event.action === 'push' && (
104 <span style="color: var(--text-muted);"> pushed to <code style="background: var(--bg-tertiary); padding: 1px 4px; border-radius: 3px;">{event.details?.ref}</code></span>
105 )}
106 {event.action === 'create_mr' && (
107 <span style="color: var(--text-muted);"> opened MR <a href={`/${owner}/${repo}/merge-requests/${event.details?.mr_number}`}>#{event.details?.mr_number}</a> {event.details?.mr_title}</span>
108 )}
109 {event.action === 'merge_mr' && (
110 <span style="color: var(--text-muted);"> merged MR <a href={`/${owner}/${repo}/merge-requests/${event.details?.mr_number}`}>#{event.details?.mr_number}</a> {event.details?.mr_title}</span>
111 )}
112 {event.action === 'create_repo' && (
113 <span style="color: var(--text-muted);"> created this repository</span>
114 )}
115 </div>
116 <span style="color: var(--text-muted); font-size: 0.75rem; white-space: nowrap;">{event.created_at}</span>
117 </div>
118 ))}
119 </div>
120 </div>
121 )}
122 </>
123 )}
124 </Repo>
125